﻿using Bmz.Application.Navigation;
using Bmz.Application.Services;
using Bmz.Auditing;
using Bmz.Authorization;
using Bmz.Authorization.Interceptors;
using Bmz.Configuration;
using Bmz.Dependency;
using Bmz.Domain.Uow;
using Bmz.Event.Bus;
using Bmz.Localization;
using Bmz.Localization.Sources;
using Bmz.Localization.Sources.Xml;
using Bmz.Modules;
using Bmz.Net.Mail;
using Bmz.Runtime.Validation.Interception;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Bmz
{
    /// <summary>
    /// Kernel (core) module of the Bmz system.
    /// No need to depend on this, it's automatically the first module always.
    /// </summary>
    public sealed class BmzKernelModule : BmzModule
    {
        private AuditingInterceptorRegistrar _auditingInterceptorRegistrar;

        public override void PreInitialize()
        {
            IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar());

            ValidationInterceptorRegistrar.Initialize(IocManager);

            //TODO: Consider to change order of Uow and Auth interceptors..?
            UnitOfWorkRegistrar.Initialize(IocManager);
            AuthorizationInterceptorRegistrar.Initialize(IocManager);

            _auditingInterceptorRegistrar = new AuditingInterceptorRegistrar(IocManager.Resolve<IAuditingConfiguration>(), IocManager);
            _auditingInterceptorRegistrar.Initialize();

            Configuration.Auditing.Selectors.Add(
                new NamedTypeSelector(
                    "Bmz.ApplicationServices",
                    type => typeof(IApplicationService).IsAssignableFrom(type)
                    )
                );

            Configuration.Localization.Sources.Add(
                new DictionaryBasedLocalizationSource(
                    BmzConsts.LocalizationSourceName,
                    new XmlEmbeddedFileLocalizationDictionaryProvider(
                        Assembly.GetExecutingAssembly(), "Bmz.Localization.Sources.BmzXmlSource"
                        )));

            Configuration.Settings.Providers.Add<EmailSettingProvider>();

            Configuration.UnitOfWork.RegisterFilter(BmzDataFilters.SoftDelete, true);
            Configuration.UnitOfWork.RegisterFilter(BmzDataFilters.MustHaveTenant, true);
            Configuration.UnitOfWork.RegisterFilter(BmzDataFilters.MayHaveTenant, true);
        }

        public override void Initialize()
        {
            base.Initialize();

            IocManager.IocContainer.Install(new EventBusInstaller(IocManager));

            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly(),
                new ConventionalRegistrationConfig
                {
                    InstallInstallers = false
                });
        }

        public override void PostInitialize()
        {
            RegisterMissingComponents();

            IocManager.Resolve<LocalizationManager>().Initialize();
            IocManager.Resolve<NavigationManager>().Initialize();
            IocManager.Resolve<PermissionManager>().Initialize();
            IocManager.Resolve<SettingDefinitionManager>().Initialize();
        }

        private void RegisterMissingComponents()
        {
            IocManager.RegisterIfNot<IUnitOfWork, NullUnitOfWork>(DependencyLifeStyle.Transient);
            IocManager.RegisterIfNot<IAuditInfoProvider, NullAuditInfoProvider>(DependencyLifeStyle.Transient);
            IocManager.RegisterIfNot<IAuditingStore, SimpleLogAuditingStore>(DependencyLifeStyle.Transient);
        }
    }
}
